package cate.game.role.res;

import cate.common.table.d.GDChat;
import cate.common.table.res.IBucketRow;
import cate.common.util.random.RWList;
import cate.game.chat.ChatFacade;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import easy.java.dev.note.NoteField;
import org.springframework.data.annotation.Transient;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

public abstract class BaseCallBucket <T extends BaseBucketItem, R extends IBucketRow> extends RoleDependent {
    @NoteField(value = "召唤木桶们", detail = "<召唤组， <xx id，木桶数据>>")
    public Map<Integer, Map<Integer, T>> callBuckets;

    @NoteField(value = "本次登录校验过的桶，不入库")
    @Transient
    private transient final List<Integer> checkedBuckets = new ArrayList<>();

    @NoteField(value = "召唤类型")
    public BucketCallType type;

    public BaseCallBucket() {

    }

    public BaseCallBucket(BucketCallType type) {
        this.type = type;
    }

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (callBuckets == null) {
            callBuckets = new HashMap<>();
        }
        if (type == null) {
            type = BucketCallType.BASE;
        }
    }

    public void clear(){
        callBuckets.clear();
        checkedBuckets.clear();
    }

    /**
     * 获取某个组的表数据
     * @param groupId groupid
     * @return List<IBucketRow>
     */
    protected abstract Map<Integer, R> getBucketRows(int groupId);

    protected abstract T createBucketItem(R row);

    /**
     * 校验身上的桶数据和表里的数据
     *
     */
    private void checkBuckets(int groupId) {
        Map<Integer, R> rowsMap = getBucketRows(groupId);
        if (rowsMap.isEmpty() || checkedBuckets.contains(groupId)) {
            return;
        }
        callBuckets.putIfAbsent(groupId, new HashMap<>());
        Map<Integer, T> buckets = callBuckets.get(groupId);
        boolean blank = CollectionUtils.isEmpty(buckets);
        Set<Integer> idSet = null;
        if (!blank) {
            idSet = new HashSet<>();
        }
        for (R bucketRow : rowsMap.values()) {
            buckets.putIfAbsent(bucketRow.getBucketItemId(), createBucketItem(bucketRow));
            if (!blank) {
                idSet.add(bucketRow.getBucketItemId());
            }
        }
        if (!blank) {
            Set<Integer> finalHeroIdSet = idSet;
            buckets.values().removeIf(c -> !finalHeroIdSet.contains(c.id));
        }
        checkedBuckets.add(groupId);
    }

    public T doBucketCall(int groupId) {
        checkBuckets(groupId);
        RWList<T> rwlist = new RWList<>();
        rwlist.addAll(callBuckets.get(groupId).values());
        rwlist.setup();
        T b = rwlist.get();
        //修改概率
        modifyRate(b, groupId, rwlist);
        return b;
    }

    private void modifyRate(T b, int groupId, RWList<T> rwlist) {
        R row = getBucketRows(groupId).get(b.id);
        b.weight -= b.weight * row.getMinusWeightPercent() / 100;
        b.weight = Math.max(b.weight, row.getMinWeight());
        recalcWeight(groupId, b.id, rwlist.list);
    }

    /**
     * 除了某个英雄外，其他英雄重新计算权重
     *
     * @param id 排除的id
     */
    private void recalcWeight(int groupId, int id, List<T> list) {
        if (type == BucketCallType.SPE_ONLY) {
            return;
        }
        R row;
        for (T t : list) {
            if (t.id != id) {
                row = getBucketRows(groupId).get(t.id);
                t.weight += row.getAddWeight();
            }
        }
    }

    public void logBucket(int groupId) {
        checkBuckets(groupId);
        Collection<T> list = callBuckets.get(groupId).values().stream().sorted(Comparator.comparingInt(e -> e.id)).collect(Collectors.toList());
        StringBuilder sb = new StringBuilder();
        int idx = 0;
        for (T bucketItem : list) {
            if (bucketItem.weight <= 0) {
                continue;
            }
            R row = getBucketRows(groupId).get(bucketItem.id);
            if (row != null) {
                sb.append(row.getBucketItemId()).append(":").append((int)bucketItem.weight).append("  ");
            }
            if(++idx % 3 == 0) {
                sb.append("\n");
            }
        }
        if (sb.length() > 0) {
            ChatFacade.sendPublicFromClient(role, GDChat.Channel.WORLD, 0, sb.toString(), null);
        }
    }
}
